#include "dcda_renew.h"
#include "ui_dcda_renew.h"

DCDA_Renew::DCDA_Renew(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::DCDA_Renew)
{
    ui->setupUi(this);

    m_sInitQSSPath = ":/qss/bluewhite/bluewhite.qss";

    if (qApp->arguments().length() > 1)
    {
        m_sInitQSSPath = qApp->arguments()[1];
        //qDebug() << "qss path:" << m_sInitQSSPath;
        if (qApp->arguments().length() > 2)
        {
            m_sAppnames = qApp->arguments()[2];
        }
    }

    InitTitlepar();
    InitQSS();

    filein.open(stdin, QIODevice::ReadOnly);
    sn = new QSocketNotifier(filein.handle(), QSocketNotifier::Read, this);
    connect(sn, SIGNAL(activated(int)), this, SLOT(ReadFromServer(int)));

    ui->label_suggest->setOpenExternalLinks(true);
    ui->label_prompt->setOpenExternalLinks(true);

    QCoreApplication::setOrganizationName("Danpe");
    QCoreApplication::setOrganizationDomain("lijianxun.cn");
    QCoreApplication::setApplicationName("CommDubugAssist");

    QSettings settings;
    m_sVer = settings.value("VERSION").toString();
    if (m_sVer.isEmpty())
    {
        ui->label_ver->setText("当前版本获取失败，请启动一次程序后，通过程序首选项设置来启动本软件。");
    }
    else
    {
        ui->label_ver->setText("当前版本：" + m_sVer);
    }

    // 获取程序所在路径
    m_sAppPath = qApp->applicationDirPath();
    //qDebug() << "path:" << m_sAppPath;
    m_url.setUrl("http://lijianxun.cn/DCDA_Update.xml");

    ReadUpDate();

    ui->progressBar->hide();
    m_selMainWidget->show();
}

DCDA_Renew::~DCDA_Renew()
{
    delete ui;
}

void DCDA_Renew::InitQSS()
{
    QFile file(m_sInitQSSPath);
    bool isOK = file.open(QFile::ReadOnly);
    if (isOK)
    {
        QTextStream filetext(&file);
        QString stylesheet = filetext.readAll();
        m_selMainWidget->setStyleSheet(stylesheet);
    }
    file.close();
}

void DCDA_Renew::InitTitlepar()
{
    QDesktopWidget* desktop = QApplication::desktop();

    m_selMainWidget = new WidgetPar; //创建一个QWidget容器
    m_selMainWidget->setWindowFlags(Qt::FramelessWindowHint);//将这个QWidget的边框去掉

    this->setParent(m_selMainWidget);//重新设置这个UI界面的父对象为QWidget
    pTitleBar = new TitleBar(m_selMainWidget); //定义一个标题栏类

    pTitleBar->showMinmizeBtn(false);
    pTitleBar->showMaxmizeBtn(false);

    this->installEventFilter(pTitleBar);//安装事件过滤器
    QGridLayout *pLayout = new QGridLayout();//创建一个整体布局器
    pLayout->addWidget(pTitleBar);  //添加标题栏
    pLayout->addWidget(this);       //添加UI界面
    pLayout->setSpacing(0);         //布局之间的距离
    pLayout->setContentsMargins(0, 0, 0, 0); //布局器的四周边距
    m_selMainWidget->setLayout(pLayout);  //将这个布局器设置在QWidget上
    m_selMainWidget->setSizePolicy(this->sizePolicy());
    m_selMainWidget->setMaximumSize(this->maximumSize());
    m_selMainWidget->setMinimumWidth(this->minimumWidth() + 2);
    if (this->minimumHeight() + pTitleBar->height() + 10 > 60)
    {
        m_selMainWidget->setMinimumHeight(this->minimumHeight() + pTitleBar->height() + 10);
    }
    else
    {
        m_selMainWidget->setMinimumHeight(pTitleBar->height() + 2);
    }
    m_selMainWidget->setGeometry((desktop->width() - this->width())/2, (desktop->height() - this->height() - pTitleBar->height())/2, this->width(), this->height() + pTitleBar->height() + 10);
    m_selMainWidget->setTitleHeight(static_cast<uint>(pTitleBar->height()));

    connect(m_selMainWidget, &WidgetPar::CloseSignal, this, &DCDA_Renew::closeEvent);

    m_selMainWidget->setWindowTitle(QString("蛋皮通信调试助手更新"));
    this->setWindowTitle(QString("蛋皮通信调试助手更新"));
    setWindowIcon(QIcon(":/image/DCDA.ico"));
}

void DCDA_Renew::ReadFromServer(int fd)
{
    //qDebug() << "read form server";
    ui->textEdit->append("read form server");
    if (fd != filein.handle())
    {
        ui->textEdit->append("read Error");
        //qDebug() << "read error";
        return ;
    }
    QString readdata;
    readdata = QString::fromLocal8Bit(filein.readLine());
    ui->textEdit->append("readdata:" + readdata);
    //qDebug() << "readdata:" << readdata;
    ui->label_prompt->setText(readdata);
}

///
/// \brief 获取更新信息
///
void DCDA_Renew::ReadUpDate()
{
    QNetworkAccessManager manager;
    QEventLoop loop;
    QNetworkReply *reply;

    reply = manager.get(QNetworkRequest(m_url));
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    QString updatecode = reply->readAll();

    QDomDocument doc;
    if (doc.setContent(updatecode))
    {
        QDomElement root = doc.documentElement();
        QDomNode dcdadatas = root.childNodes().at(0);
        if (dcdadatas.hasAttributes())
        {
            QDomNamedNodeMap attrs = dcdadatas.attributes();
            for (int i = 0; i < attrs.count(); i++)
            {
                QDomNode n = attrs.item(i);
                QString nodeName = n.nodeName();
                QString nodeValue = n.nodeValue();
                if (nodeName == "VERSION")
                {
                    if (!nodeValue.isEmpty())
                    {
                        m_sNewVer = nodeValue;
                        ui->label_newver->setText("最新版本：" + m_sNewVer);
                    }
                }
                else if (nodeName == "Date")
                {
                    if (!nodeValue.isEmpty())
                    {
                        m_sDate = nodeValue;
                        ui->label_date->setText("更新日期：" + m_sDate);
                    }
                }
#if defined (Q_OS_LINUX)
                else if (nodeName == "linux_url")
                {
                    if (!nodeValue.isEmpty())
                    {
                        m_sDownPath = nodeValue;
                    }
                }
#elif defined (Q_OS_WIN)
                else if (nodeName == "win_url")
                {
                    if (!nodeValue.isEmpty())
                    {
                        m_sDownPath = nodeValue;
                        //qDebug() << "m_sDownpath:" << m_sDownPath;
                    }
                }
#else
                ui->label_newver->clear();
                ui->label_date->clear();
                ui->label_newver->hide();
                ui->label_date->hide();
                ui->btn_update->setEnabled(false);
                ui->btn_cancel->setText("关闭");
                ui->label_prompt->setText("<style> a {text-decoration: none} </style>暂不支持当前系统的自动更新！您可以选择针对您操作系统的<a href=\"http://lijianxun.cn/dcda\">手动更新</a>。如有其他建议与疑问，欢迎点击左下角反馈。");
                return ;
#endif
            }
        }
        if (dcdadatas.hasChildNodes())
        {
            QDomNodeList upcontents = dcdadatas.childNodes();
            for (int i = 0; i < upcontents.count(); i++)
            {
                QDomNode upcontent = upcontents.at(i);
                if (upcontent.hasAttributes())
                {
                    QDomNamedNodeMap attrs = upcontent.attributes();
                    for (int i = 0; i < attrs.count(); i++)
                    {
                        QDomNode n = attrs.item(i);
                        QString nodeName = n.nodeName();
                        QString nodeValue = n.nodeValue();
                        if (nodeName == "upcontent")
                        {
                            if (!nodeValue.isEmpty())
                            {
                                m_sUpContents.append(nodeValue);
                            }
                        }
                    }
                }
            }
        }
        m_bGetUpdate = true;
        if (m_sVer == m_sNewVer)
        {
            m_bCanUpdate = false;
            ui->btn_update->setEnabled(false);
            ui->btn_cancel->setText("关闭");
            ui->label_prompt->setText("当前已是最新版本，无需更新");
        }
        else
        {
            m_bCanUpdate = true;
            ui->label_prompt->setText("有最新版本可更新，是否更新？");
            ui->btn_cancel->setText("取消");
        }
        if (m_sUpContents.length() > 0)
        {
            QString showcontents = "新版更新内容：";
            if (m_sVer == m_sNewVer)
            {
                showcontents = "当前版本更新日志：";
            }
            for (int i = 0; i < m_sUpContents.length(); i++)
            {
                showcontents.append("\n  " + QString::number(i+1) + ". " + m_sUpContents[i]);
            }
            showcontents.append("\n");
            ui->textEdit->setText(showcontents);
        }
    }
    else
    {
        m_bGetUpdate = false;
        m_bCanUpdate = false;
        ui->label_prompt->setText("<style> a {text-decoration: none} </style>更新内容获取失败！您可以点击重新获取或者选择<a href=\"http://lijianxun.cn/dcda\">手动更新</a>");
        ui->btn_update->setText("重新获取");
        ui->label_newver->clear();
        ui->label_date->clear();
        ui->label_newver->hide();
        ui->label_date->hide();
    }
}

///
/// \brief 关闭/取消
///
void DCDA_Renew::on_btn_cancel_clicked()
{
    if (m_nUpdateState == 0 || m_nUpdateState == 10)
    {
        m_selMainWidget->close();
    }
    else
    {
        bool isOK = AskInform("更新尚未完成，确认退出吗？");
        if (isOK)
        {
            m_selMainWidget->close();
        }
    }
}

///
/// \brief 重新获取/更新软件
///
void DCDA_Renew::on_btn_update_clicked()
{
    if(m_bGetUpdate == false)
    {
        ReadUpDate();
    }
    else
    {
        if (m_sAppnames.isEmpty())
        {
            inform("当前窗口无法自动更新！可支持手动下载更新。如需自动更新请先关闭本界面并通过软件主程序来启动此界面。");
            return ;
        }
        // 可以下载更新
        if (m_bCanUpdate && (!m_sDownPath.isEmpty()))
        {
            if (m_nUpdateState == 5 || m_nUpdateState == 7)
            {
                updateStart();
            }
            else
            {
                m_nUpdateState = 1;
                ui->btn_update->setEnabled(false);
                CheckAndEstablishFiles(m_sAppPath + "/Update/Download");
                ui->label_prompt->setText("正在连接目标服务器");

                //m_sDownPath = "https://mirrors.tuna.tsinghua.edu.cn/kicad/windows/stable/kicad-5.1.6_1-x86_64.exe";
                //m_sDownPath="http://lijianxun.cn/wp-content/uploads/2020/04/%E8%9B%8B%E7%9A%AE%E9%80%9A%E8%AE%AF%E8%B0%83%E8%AF%95%E5%8A%A9%E6%89%8B_win.zip";
                m_DownUrl.setUrl(m_sDownPath);
                qDebug() << "file name:" << m_DownUrl.fileName();

                QString filename = m_DownUrl.fileName();
                if (filename.isEmpty())
                {
#if defined (Q_OS_WIN)
                    filename = "DCDA_win_" + m_sNewVer.remove(' ') + ".exe";
#elif defined (Q_OS_LINUX)
                    filename = "DCDA_linux_" + m_sNewVer.remove(' ');
#else
                    filename = "DCDA_" + m_sNewVer.remove(' ');
#endif
                }

    //            // 判断下载文件是否存在
    //            bool exist = QFile::exists(m_sAppPath + "/Update/Download/" + filename);

                m_file = new QFile(m_sAppPath + "/Update/Download/" + filename);
                if (!m_file->open(QIODevice::WriteOnly))
                {
                    inform("文件存储错误");
                }
                m_sFilename = filename;

                QNetworkRequest request;
                m_DownManager = new QNetworkAccessManager(this);
                request.setUrl(m_DownUrl);

                // 断点续传
                QString strRange = QString("bytes=%1-").arg(m_bytesCurrentReceived);
                request.setRawHeader("Range", strRange.toLatin1());

                m_DownReply = m_DownManager->get(request);
                connect(m_DownReply, SIGNAL(readyRead()), this, SLOT(ReadyRead()));
                connect(m_DownReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(updateDataReadProgress(qint64, qint64)));
                connect(m_DownReply, SIGNAL(finished()), this, SLOT(Finished()));
                ui->progressBar->setValue(0);
                ui->progressBar->show();
            }
        }
        else  // 不可以下载更新
        {
            ui->btn_update->setEnabled(false);
        }
    }
}

void DCDA_Renew::ReadyRead()
{
    if (m_file)
        m_file->write(m_DownReply->readAll());
}

///
/// \brief 更新进度条
/// \param bytesRead
/// \param bytesTotal
///
void DCDA_Renew::updateDataReadProgress(qint64 bytesRead, qint64 bytesTotal)
{
    ui->progressBar->setMaximum(static_cast<int>(bytesTotal));
    ui->progressBar->setValue(static_cast<int>(bytesRead));
    //qDebug() << "readvalue:" << bytesRead << ", allvalue" << bytesTotal;
    int readkb = static_cast<int>(bytesRead/1024);
    int readmb = readkb/1024;
    readkb = readkb%1024;
    QString showreadnum;
    if (readmb == 0)
    {
        showreadnum = QString::number(readkb) + "kb";
    }
    else
    {
        showreadnum = QString::number(readmb) + "." + QString::number((readkb*10)/1024) + + "Mb";
    }

    int allkb = static_cast<int>(bytesTotal/1024);
    int allmb = allkb/1024;
    allkb = allkb%1024;
    QString showallnum;
    if (allmb == 0)
    {
        showallnum = QString::number(allkb) + "kb";
    }
    else
    {
        showallnum = QString::number(allmb) + "." + QString::number((allkb*10)/1024) + "Mb";
    }

    if (bytesRead == bytesTotal)
    {
        ui->label_prompt->setText("下载完成 --- 当前：" + showreadnum + " 总计：" + showallnum);
    }
    else
    {
        ui->label_prompt->setText("正在下载中 --- 当前：" + showreadnum + " 总计：" + showallnum);
    }
}
void DCDA_Renew::Finished()
{
    m_file->flush();
    m_file->close();
    m_DownReply->deleteLater();
    m_DownReply = nullptr;
    delete m_file;
    m_file = nullptr;
    bool isOK = AskInform("更新文件下载完成，是否立即重启软件？");
    m_nUpdateState = 5;

    if (isOK)
    {
        ui->label_prompt->setText("正在重启软件");
        updateStart();
    }
    else
    {
        ui->btn_update->setText("重启");
        ui->btn_update->setEnabled(true);
    }
}

void DCDA_Renew::updateStart()
{
    m_nUpdateState = 7;

    // 给主界面程序发送关闭指令
    QTextStream qout(stdout);
    qout << "exit" << endl;

    // 等待主界面程序关闭
    MySleep(100);

    CheckAndEstablishFiles(m_sAppPath + "/Update/OldApp");
    QString oldname;
#if defined (Q_OS_WIN)
    oldname = "DCDA_win_" + m_sVer.remove(' ') + ".exe";
#elif defined (Q_OS_LINUX)
    oldname = "DCDA_linux_" + m_sVer.remove(' ');
#else
    oldname = "DCDA_" + m_sVer.remove(' ');
#endif
    int num = 1;
    QString samename = oldname;
    while (QFile::exists(m_sAppPath + "/Update/OldApp/" + samename))
    {
        num++;
#if defined (Q_OS_WIN)
        samename = "DCDA_win_" + m_sVer.remove(' ') + "_" + QString::number(num) + ".exe";
#elif defined (Q_OS_LINUX)
        samename = "DCDA_linux_" + m_sVer.remove(' ') + "_" + QString::number(num);
#else
        samename = "DCDA_" + m_sVer.remove(' ') + "_" + QString::number(num);
#endif
    }
    oldname = samename;
    bool ok = QFile::copy(m_sAppPath + "/" + m_sAppnames, m_sAppPath + "/Update/OldApp/" + oldname);
    if (!ok)
    {
        inform("Error，请手动更新");
        return ;
    }
    ok = QFile::remove(m_sAppPath + "/" + m_sAppnames);
    if (!ok)
    {
        inform("Error，请手动更新");
        return ;
    }
    ok = QFile::copy(m_sAppPath + "/Update/Download/" + m_sFilename, m_sAppPath + "/" + m_sAppnames);
    if (!ok)
    {
        inform("Error，请手动更新");
        return ;
    }
    m_pro = new QProcess(this);
    ok = m_pro->startDetached(m_sAppPath + "/" + m_sAppnames);
    if (!ok)
    {
        inform("软件打开失败！");
        return ;
    }
    else
    {
        m_nUpdateState = 10;
        m_selMainWidget->close();
    }
}

void DCDA_Renew::MySleep(unsigned int msec)
{
    if (msec == 0)
    {
        return ;
    }
    QTime reachTime = QTime::currentTime().addMSecs(static_cast<int>(msec));
    while (QTime::currentTime() < reachTime)
        QCoreApplication::processEvents(QEventLoop::AllEvents, 10);
}

///
/// \brief 检查文件路径是否存在，没有则创建文件路径
/// \param path
/// \return 创建是否成功
///
bool DCDA_Renew::CheckAndEstablishFiles(QString path)
{
    QDir dir;
    if (!dir.exists(path))
    {
        bool isOK = dir.mkpath(path);
        return isOK;
    }
    return true;
}

///
/// \brief 通知
/// \param strdata
///
void DCDA_Renew::inform(QString strdata)
{
    QMessageBox m_r;

    WidgetPar *wid;
    wid = new WidgetPar;
    wid->setWindowFlags(Qt::FramelessWindowHint);
    wid->setWindowModality(Qt::ApplicationModal);
    m_r.setParent(wid);
    TitleBar *titbar = new TitleBar(wid);

    titbar->showMinmizeBtn(false);
    titbar->showMaxmizeBtn(false);
    titbar->EnableCloseBtn(false);

    m_r.installEventFilter(titbar);
    QGridLayout *layout = new QGridLayout();

    m_r.setText(strdata);

    layout->addWidget(titbar);  //添加标题栏
    layout->addWidget(&m_r);       //添加UI界面
    layout->setSpacing(0);         //布局之间的距离
    layout->setContentsMargins(0, 0, 0, 0); //布局器的四周边距
    wid->setLayout(layout);  //将这个布局器设置在QWidget上
    wid->setSizePolicy(m_r.sizePolicy());
    wid->setMaximumSize(m_r.maximumSize());
    wid->setMinimumWidth(m_r.minimumWidth() + 2);

    wid->setWidgetResizable(false);

    wid->move(m_selMainWidget->x() + (m_selMainWidget->width() - 150 - 3*strdata.length())/2, m_selMainWidget->y() + (m_selMainWidget->height() - (titbar->height() + 50))/2);
    wid->setTitleHeight(static_cast<uint>(titbar->height()));

    m_r.setWindowTitle("提示");
    m_r.setWindowIcon(QIcon(":/image/DCDA.ico"));

    QFile file(m_sInitQSSPath);
    bool isOK = file.open(QFile::ReadOnly);
    if (isOK)
    {
        QTextStream filetext(&file);
        QString stylesheet = filetext.readAll();
        wid->setStyleSheet(stylesheet);
    }
    file.close();

    wid->show();
    m_r.exec();
    wid->close();
    titbar->deleteLater();
    layout->deleteLater();
    wid->deleteLater();
    titbar = nullptr;
    layout = nullptr;
    wid = nullptr;
}

///
/// \brief 弹窗询问
/// \param strdata
/// \return 返回询问结果
///
bool DCDA_Renew::AskInform(QString strdata)
{
    QMessageBox m_r;

    WidgetPar *wid;
    wid = new WidgetPar;
    wid->setWindowFlags(Qt::FramelessWindowHint);
    wid->setWindowModality(Qt::ApplicationModal);
    m_r.setParent(wid);
    TitleBar *titbar = new TitleBar(wid);

    titbar->showMinmizeBtn(false);
    titbar->showMaxmizeBtn(false);
    titbar->EnableCloseBtn(false);

    m_r.installEventFilter(titbar);
    QGridLayout *layout = new QGridLayout();

    layout->addWidget(titbar);  //添加标题栏
    layout->addWidget(&m_r);       //添加UI界面
    layout->setSpacing(0);         //布局之间的距离
    layout->setContentsMargins(0, 0, 0, 0); //布局器的四周边距
    wid->setLayout(layout);  //将这个布局器设置在QWidget上


    wid->setWidgetResizable(false);

    wid->setTitleHeight(static_cast<uint>(titbar->height()));

    m_r.setWindowTitle("提示");
    m_r.setWindowIcon(QIcon(":/image/DCDA.ico"));
    m_r.setText(strdata);
    m_r.addButton(tr("确认"), QMessageBox::ActionRole);
    m_r.addButton(tr("取消"), QMessageBox::ActionRole);

    wid->setSizePolicy(m_r.sizePolicy());
    wid->setMaximumSize(m_r.maximumSize());
    wid->setMinimumWidth(m_r.minimumWidth() + 2);

    int length = strdata.length();
    if (length > 74)
    {
        length = 74;
    }
    //qDebug() << "this x:" << m_selMainWidget->x() << ", y:" << m_selMainWidget->y() << ", width:" << m_selMainWidget->width() << ", height:" << m_selMainWidget->height();
    //qDebug() << "m_r width:" << m_r.width() << ", height:" << m_r.height() << ", titbar height:" << titbar->height();
    wid->move(m_selMainWidget->x() + (m_selMainWidget->width() - 150 - 3*length)/2, m_selMainWidget->y() + (m_selMainWidget->height() - (titbar->height() + 50))/2);

    //qDebug() << "wid x:" << wid->x() << ", y" << wid->y() << ", width" << wid->width() << ", height" << wid->height();

    QFile file(m_sInitQSSPath);
    bool isOK = file.open(QFile::ReadOnly);
    if (isOK)
    {
        QTextStream filetext(&file);
        QString stylesheet = filetext.readAll();
        wid->setStyleSheet(stylesheet);
    }
    file.close();

    if (pTitleBar->getLockState())
    {
        Qt::WindowFlags m_flags = wid->windowFlags();
        wid->setWindowFlags(m_flags | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
    }
    wid->show();
    int isok = m_r.exec();
    wid->close();
    titbar->deleteLater();
    layout->deleteLater();
    wid->deleteLater();
    titbar = nullptr;
    layout = nullptr;
    wid = nullptr;
    if (isok == 1)
    {
        return false;
    }
    else
    {
        return true;
    }
}

//void DCDA_Renew::on_btn_test_clicked()
//{
//    QFile fileout;
//    fileout.open(stdout, QIODevice::WriteOnly);
//    QString senddata = "exit\n";
//    fileout.write(senddata.toLatin1().constData(), senddata.length());
//    qWarning();
//    fileout.close();
////    QTextStream qout(stdout);
////    qout << "exit" << endl;
//}
